跳到主要内容

SpringMVC 接收参数

获取请求参数的几种方式

参考资料 springMVC接收参数的几种形式 参考资料 目前为止全网最全的 SpringBoot 参数传递方案

使用形参来接收

Controller 中的业务方法的形参名称要与请求参数的 name 一致,参数值会自动匹配映射

这个适合 Get 请求

/**
* 直接把表单的参数写在Controller相应的方法的形参中
* @param username
* @param password
* @return
*/
@GetMapping("/addUser1")
public String addUser1(String username,String password) {
System.out.println("username is:"+username);
System.out.println("password is:"+password);
return "demo/index";
}

绑定请求参数

上面使用形参必须对应请求参数名,可以使用注解 @RequestParam 绑定请求参数到形参上

用注解 @RequestParam 绑定请求参数到方法入参, POST 方式的时候编码方式需设置为:x-www-form-urlencoded, 不能接受 JSON

@GetMapping("/doLogin")
public User doLogin(@RequestParam(value="name") String username, @RequestParam(value="pwd") String password) {
logger.info("name: " + username);
logger.info("pwd: " + password);
User user = new User();
user.setPwd(password);
user.setName(username);
return user;
}

获取数组类型参数

Controller 中的业务方法的 数组名称与请求参数的 name 一致时,参数值会自动映射匹配

http://localhost:8080/test?strs=111&strs=222&strs=333
@RequestMapping("/test")
public String addUser1(String[] strs) {
System.out.println(Arrays.asList(strs));
}

Post 请求获取参数

关键是要使用 @RequestBody 注解来获取响应体里的内容

@PostMapping("/login")
public String login(@RequestBody User user) {
log.info(user.toString());
return "ok";
}

HttpServletRequest 获取

/**
* 2、通过HttpServletRequest接收
* @param request
* @return
*/
@RequestMapping("/addUser2")
public String addUser2(HttpServletRequest request) {
String username=request.getParameter("username");
String password=request.getParameter("password");
System.out.println("username is:"+username);
System.out.println("password is:"+password);
return "demo/index";
}

接收表单数据

  • @RequestBody 注解,必须与 contentType 类型 application/json 配合使用。
  • @RequestParam 注解,必须与 contentType 类型 application/x-www-form-urlencoded 配合使用,其为默认类型。
  • JSON.stringify() 把对象类型转换为字符串类型,一般配合 @RequestBody 注解和 contentType 类型 application/json 使用。

RestFul 风格

就是一个不同于传统那种直接 ?id=1&name=Lisa 那样带参数的请求 而是直接把这个参数写入地址里,通过自定义的方法来读取出来

# 传统
http://127.0.0.1/project?id=1&name=Lisa
# 使用RestFul风格
http://127.0.0.1/project/1/Lisa

注意:这玩意不是一种标准或者协议,只是一种风格

// http://localhost:8080/test/1/4
@Controller
public class RestFulController {

@RequestMapping("/test/{p1}/{p2}")
public String test(@PathVariable("p1") int a, @PathVariable("p2") int b, Model model) {
model.addAttribute("msg", "结果为:" + (a + b));
return "test";
}
}

获取请求头

使用 @RequestHeader 获取请求头信息

使用 @RequestHeader 可以获取请求头的信息,相当于 JavaWeb 里的 request.getHeader(name)

@RequestHeader 注解主要的属性

  • value:请求头名称
  • required:是否必须携带此请求头

使用例

@RequestMapping("/test")
public String test(@RequestHeader(value = "User-Agent", required = true) String headerValue) {
System.out.println(headerValue);
}

使用 @CookieValue 可以获取指定 Cookie 的值

  • value:指定 cookie 的名称
  • required:是否必须携带此 cookie

使用例

@RequestMapping("/test")
public String test(@CookieValue(value = "USERID", required = true) String userid) {
System.out.println(userid);
}

自定义类型转换器

注意:在后面的版本引入了 HttpMessageConverter 用来自定义转换器,具体区别看 SpringBoot 整合 MVC 那篇笔记

SpringMVC 默认已经提供了一些常用的类型转换器,例如客户端提交的字符串能自动转成 int 类型再传入形参

但是有些还需要自定义的转换器,例如传入一个日期的数据进来(例如这篇博客用的日期就是 2020-08-16)这种情况就需要自定义类型转换器

注意:因为传入的数据全都是字符串,所以类型转换器的策略一般是优先匹配自定义的类型转换器,匹配失败换下一个转换器(官方默认的),全部转换器都匹配失败则报错

自定义类型转换器的开发步骤

1、定义转换器类实现 Converter 接口

2、在配置文件中声明转换器

3、在 <annotation-driven> (注解驱动)中引用转换器

创建 Converter 实现类

public class DataConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = format.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}

声明这个 Converter

<!-- 注意:这个 mvc:annotation-driven 的支持是 
xmlns:mvc="http://www.springframework.org/schema/mvc" 别引用错了 -->

<!--声明转换器-->
<bean id="ConversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.alsritter.converter.DataConverter"/>
</list>
</property>
</bean>

<!-- 把这个转换器加入到驱动里 -->
<mvc:annotation-driven conversion-service="ConversionService"/>

接收 JSON

当接收 JSON 形式的参数一般都是在响应体里取得的,所以需要使用 @RequestBody 注解

使用 Map

@PostMapping("/multiParameter")
public Result register(@RequestBody Map<String,Object> map){
log.info("多参数传递:{},{}",map.get("title"),map.get("content"));
//业务逻辑
return Result.ok("接收多参数成功");
}

参数封装到 Entity

Controller 中的业务方法的实体对象参数的属性名称与请求参数的 name 一致时,参数值会自动映射匹配

// 参数?key1=val1&key2=val2的方式加在url后面即可。

@RequestMapping("/doLogin")
public User doLogin(User u) {
logger.info("name: " + u.getName());
logger.info("pwd: " + u.getPwd());
User user = new User();
user.setName(u.getName());
user.setPwd(u.getPwd());
return user;
}

注意:类中属性必须为 public;且类中的属性只能比 json 中的属性多,不能少,因为 Spring 是通过 setter 方法注入进去的

接收的是复杂类型

参考资料 springmvc接收复杂类型的json数据需要注意的地方

如果接收的是普通的数据类型或者单对象,后端的方法上面什么也不需要处理,只需要将对象放入到参数上面就可以了

但是如果接收的是复杂类型,例如对象里面还包含对象或者是集合等,后端的方法参数上面只需要加上 @RequestBody 即可,但是还没有完,前端传递的时候需要加上 contentType:application/json

如下实例:

public class SignUpSave {

private Integer taskID;
private Integer skillID;
List<SignUpSave.Data> equipment = new ArrayList<SignUpSave.Data>();
/*...*/
public static class Data{
private Integer equipmentDetailID;
private Integer qty;
/*...*/
}
}

Controller 的方法:

public SignUpResult SignUp(HttpServletRequest request,@RequestBody SignUpSave signUpSave) throws Exception{
/*...*/
return signUpResult;
}

前端发送的数据:

var test = {
"TaskID": "1",
"SkillID": "1",
"Equipment": [
{
"EquipmentDetailID": "1",
"Qty": "1"
}
]
};

$.ajax({
type: "POST",
url:"...",
contentType: "application/json",
data: JSON.stringify(test),
dataType: "json",
success:function(res){
console.log(res)
}
})

接收多个对象

如果使用 SpringMvc 同客户端通信,完全使用 json 数据格式,例如 {name:"test"},name 为 User 类的属性值

@Controller
public class TestController{
@RequestMapping("\test")
@ResponseBody
public ReturnResult test(@RequestBody User user){
return new ReturnResult();
}
}

注意:类中属性必须为 public;且类中的属性只能比 json 中的属性多,不能少,因为 Spring 是通过 setter 方法注入进去的

但是有时接收 json 格式数据时,我们可能需要将其转换为多个对象 {user:{name:"test"},address:{location:"新华路"}} ,如果 Controller 写成下面这样则是错误的

@Controller
public class TestController{
@RequestMapping("\test")
@ResponseBody
public RetureResult test(@RequestBody User user, @RequestBody Address address){
return new ReturnResult();
}
}

如上代码,同时接收了两次对象,这样是错误的!因为 Request 的 Body 是以流的形式进行读取的,读取完一次后,便无法再次读取了

此时可使用包装类的方法来接收多个对象

class Param{
public User user;
public Address address;
}
@Controller
public class TestController{
@RequestMapping("\test")
@ResponseBody
public ReturnResult test(@RequestBody Param param){
return new ReturnResult();
}
}

获取集合对象

一般发送数组都是使用 JSON 的型式,所以直接使用实体对象接收就行了

使用 ajax 发送请求

let userList = new Array();
userList.push(username: "张三", password: '123')
userList.push(username: "李四", password: '123')

$.ajax({
type: "post",
url: "/test",
data: JSON.stringify(userList),
contentType: "application/json;charset=utf-8"
})

接收请求

@RequestMapping("/test")
public String test(@RequestBody List<User> userList) {
userList.forEach(System.out::println);
}

先创建一个类来接受集合对象

// Lombok
@Data
public class UserListData {
private List<User> userList;
}

接受参数

@PostMapping("/test")
public String test(@RequestBody UserListData list) {
list.forEach(System.out::println);
}

注:可以使用表单来发送集合

<form action="/test" method="post">
<!-- 传入数据的 name 带有下标(且名称要和 List 属性的名称一样) -->
<input type="text" name="userList[0].username">
<input type="text" name="userList[0].password">

<input type="text" name="userList[1].username">
<input type="text" name="userList[1].password">

<input type="text" name="userList[2].username">
<input type="text" name="userList[2].password">

<input type="submit" value="提交">
</form>

post 提交显示乱码

自定义的过滤器

public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
// 需要把这个链传递下去,让下一个过滤器执行(如果没有过滤器了就直接传给 Controller)
chain.doFilter(request,response);
}
}

然后在 web.xml 里面注册这个 Filter

注意字符编码过滤器要使用 /* 来处理所有的请求

<filter>
<filter-name>myencoding</filter-name>
<filter-class>com.alsritter.filters.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myencoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Spring 的过滤器

<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>encodingFilter</filter-name>
<!-- 注意这里的 /* 表示所有的请求都进行过滤 -->
<url-pattern>/*</url-pattern>
</filter-mapping>

注解的方式

前言:这种方式适合返回 json 或者 xml 这类数据时用

响应返回显示乱码 通过控制台(浏览器的F12)查看文件头里的 Content-Type: text/html;charset=ISO-8859-1 可以得知默认的返回编码是 IOS-8859-1 可以通过以下的方法解决:

注解 RequestMapping 中 produces 属性 指定响应体返回类型和编码

但是 必须要和 @ResponseBody 注解一起使用才可以 :因为不加 @ResponseBody 则是默认交给视图解析器去当作页面返回去了,设置响应体类型就莫得意义

通过 @RequestMapping 注解添加 produces = "text/html;charset=utf-8"

@RequestMapping(value = "/test1",produces = "text/html;charset=utf-8")
@ResponseBody
public String test(@RequestParam String name){
System.out.println(name);
return name;
}

但是用这种办法,这种方式适合返回 json 或者 xml 这类数据时用,且只能作用一个,所以如果要批量修改编码还是得靠下面的那种

使用 SpringMVC 带的工具

通过修改springmvc配置文件

这个主要作用于 @ResponseBody 响应,作用同方式二,只不过这个是全局的

实际就是 对注解解析添加一些工具(例如这里的消息转换器)

<mvc:annotation-driven>
<!--之所以需要在这里配置是因为这个信息转换器是针对@ResponseBody注解的-->
<mvc:message-converters>
<!--json 乱码问题配置-->
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="utf-8"/>
</bean>

<!--配置 json 映射的工具,这里使用 GSON-->
<bean class="org.springframework.http.converter.json.GsonHttpMessageConverter">
<property name="gson">
<bean class="com.google.gson.Gson"/>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>

@RequestParam 和 @RequestBody 区别

POST、GET 的 @RequestBody 和 @RequestParam 区别

注解 @RequestParam 接收的参数是来自 HTTP 请求体或请求 url 的 QueryString 中。

注意:application/x-www-form-urlencoded 不能使用 @RequestBody,只能使用 @RequestParam

JSON 必须使用 @RequestBody